<?php


namespace app\madmin\service;

use app\index\model\IntegralRecord;
use app\madmin\model\IntegralAttrName;
use app\madmin\model\IntegralAttrValue;
use app\madmin\model\IntegralClassify;
use app\madmin\model\IntegralGoods;
use app\madmin\model\IntegralOrder;
use app\madmin\model\IntegralSku;
use app\madmin\model\IntegralSkuInventory;
use app\madmin\model\UserCash;
use think\Collection;
use think\Exception;
use think\Model;
class IntegralShopSerivce
{
    protected $mid;
    public function __construct()
    {
        global $user;
        $this->mid = $user['mall_id'];
    }

    /**
     * 商品列表
     * @param int $page
     * @param int $size
     * @param array $data
     * @return array
     * @throws \think\db\exception\DbException
     */
    public function goodsList(int $page, int $size, array $data){
        $where[] = ['mall_id','=',$this->mid];
        !empty($data['name']) && $where[] = ['name','like','%'.$data['name'].'%'];
        $list = IntegralGoods::where($where)
            ->field('id,name,subtitle,master,status,slideshow,total,sell,sell_price,create_time')
            ->order('sort DESC,create_time DESC')
            ->with(['sku' => function($sql){$sql->with(['inventory']);}])
            ->append(['status_text'])
            ->paginate(['page' => $page,'list_rows' => $size]);
        return [HTTP_SUCCESS,$list];
    }

    /**
     * 商品详情
     * @param int $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function goodsFind(int $id) : array{
        $data = IntegralGoods::with([
            'sku' => function($sql){
                $sql->with(['inventory']);
            }
        ])->find($id);
        return [HTTP_SUCCESS,$data];
    }

    /**
     * 商品创建
     * @param array $data
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function goodsCreate(array $data) : array{
        global $user;
        $data['mall_id'] = $user['mall_id'];
        $data['merchant_id'] = \app\madmin\model\Merchant::where('mall_id',$user['mall_id'])->where('is_self',1)->value('id');
        $this->changeDataForMinAndMaxPrice($data);
        $goods = IntegralGoods::create($data);
        if (!empty($data['has_sku'])) {
            $this->updateAttr($goods, $data,'AttrSave');
            $this->saveSkuInventoryList($goods, $data['sku']);
        }
        return [HTTP_SUCCESS,$goods];
    }

    /**
     * 商品更新
     * @param int $id
     * @param array $data
     * @return bool
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function goodsUpdate(int $id, array $data) : array{
        $find = IntegralGoods::find($id);
        $this->changeDataForMinAndMaxPrice($data);
        if (!empty($data['has_sku']))
            $data['total'] = bcadd($data['total'], $find->sell, 0);
        if (!empty($data['has_sku']))
            $this->updateAttr($find, $data,'AttrUpdate');
        if (empty($data['has_sku']))
            $this->updateNullSkuAndStore($id);
        else
            $this->updateHasSkuAndNullStore($find, $data);
        $find->save($data);
        return [HTTP_SUCCESS,$find];
    }

    /**
     * 删除商品
     * @param int $id
     * @return bool
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function goodsDelete(int $id) : bool{
        $goods = IntegralGoods::find($id);
        if (empty($goods))
            throw new Exception('商品不存在',HTTP_NOTACCEPT);
        return $goods->delete();
    }
//---------------------order

    /**
     * 订单列表
     * @param int $page
     * @param int $size
     * @param array $data
     * @return array
     * @throws \think\db\exception\DbException
     */
    public function orderList(int $page, int $size, array $data){
        $where[] = ['status','>',0];
        $where[] = ['mall_id','=',$this->mid];
        $list = IntegralOrder::where($where)
            ->with(['orderCommodity' => function($sql){
                $sql->with(['goods','sellPrice','pvsValue']);
            }])
            ->order('create_time DESC')
            ->paginate(['page' => $page,'list_rows' => $size]);
        return [HTTP_SUCCESS,$list];
    }

    /**
     * 订单详情
     * @param int $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderFind(int $id){
        $data = IntegralOrder::with([
            'user' => function($sql){
                $sql->field('id,nickname,name,picurl,mobile');
            },
            'orderCommodity' => function($sql){
                $sql->with(['goods','sellPrice','pvsValue']);
            },
            'store'])
            ->find($id);
        return [HTTP_SUCCESS,$data];
    }

    /**
     * 订单发货
     * @param int $id
     * @param array $data
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderDeliver(int $id, array $data) : array{
        $order = IntegralOrder::with(['orderCommodity'])->find($id);
        if (empty($order))
            throw new Exception('订单不存在',HTTP_NOTACCEPT);
        $order->save(['status' => 2]);
        $order->orderCommodity->save([
            'status' => 2,
            'express_company' => $data['express_company'],
            'logistics_no' => $data['logistics_no'],
            'deliver_time' => date('Y-m-d H:i:s')
        ]);
        return [HTTP_SUCCESS,IntegralOrder::with(['orderCommodity'])->find($id)];
    }

    /**
     * 订单收货
     * @param int $id
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderReceiving(int $id) : array{
        $order = IntegralOrder::with(['orderCommodity'])->find($id);
        if (empty($order))
            throw new Exception('订单不存在',HTTP_NOTACCEPT);
        $order->save(['status' => 3]);
        $order->orderCommodity->save(['status' => 3,'receiving' => date('Y-m-d H:i:s')]);
        return [HTTP_SUCCESS,IntegralOrder::with(['orderCommodity'])->find($id)];
    }

    /**
     * 订单退货
     * @param int $id
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderRefund(int $id){
        $order = IntegralOrder::find($id);
        if (empty($order->id))
            throw new Exception('订单不存在',HTTP_NOTACCEPT);
        if ($order->status == 3)
            throw new Exception('收货的订单不允许退回',HTTP_NOTACCEPT);
        $order->save(['status' => 4]);
        $order->orderCommodity->save(['status' => 4,'delete_time' => date('Y-m-d H:i:s')]);
        $user = UserCash::where('user_id',$order->user_id)->lock(true)->find();
        IntegralRecord::create(['user_id' => $user->user_id,'mall_id' => $user->mall_id,'type' => 11,'status' => 1,'order_id' => $order->id,'integral' => $order->money]);
        $user->save(['integral' => $user->integral + $order->money,'integral_withdraw' => $user->integral_withdraw - $order->money]);
        return [HTTP_SUCCESS,'成功'];
    }

    /**
     * 订单删除
     * @param int $id
     * @return bool
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderDelete(int $id) : bool{
        $order = IntegralOrder::find($id);
        if (empty($order))
            throw new Exception('订单不存在',HTTP_NOTACCEPT);
        return $order->delete();
    }


    /**
     * 发货更新
     * @param int $id
     * @param array $data
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderDeliverUpdate(int $id, array $data) : void{
        $order = IntegralOrder::find($id);
        if (empty($order->id))
            throw new Exception('订单不存在',HTTP_NOTACCEPT);
        if ($order->status == 3)
            throw new Exception('收货的订单不允许退回',HTTP_NOTACCEPT);
        $order->save($data);
        return ;
    }
//--------------------------classify

    /**
     * 创建分类
     * @param array $data
     * @return array
     */
    public function classifyCreate(array $data) : array{
        $data['mall_id'] = $this->mid;
        $data = IntegralClassify::create($data);
        return [HTTP_SUCCESS,$data];
    }

    /**
     * 分类列表
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function classifyList() : array{
        $list = IntegralClassify::where('mall_id',$this->mid)->select();
        return [HTTP_SUCCESS,$list];
    }

    /**
     * 分类详情
     * @param int $id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function classifyFind(int $id) : array{
        $find = IntegralClassify::find($id);
        return [HTTP_SUCCESS,$find];
    }

    /**
     * 分类更新
     * @param int $id
     * @param array $data
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function classifyUpdate(int $id, array $data) : array{
        $find = IntegralClassify::find($id);
        if (empty($find))
            throw new Exception('数据不存在',HTTP_NOTACCEPT);
        $find->save($data);
        return [HTTP_SUCCESS,'成功'];
    }

    /**
     * 分类删除
     * @param int $id
     * @return array
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function classifyDelete(int $id) : array{
        $find = IntegralClassify::find($id);
        if (empty($find))
            throw new Exception('数据不存在',HTTP_NOTACCEPT);
        $find->delete();
        return [HTTP_SUCCESS,'成功'];
    }
//-----------------------------其他方法
    //最大最小价格
    public function changeDataForMinAndMaxPrice(array &$data) : void
    {
        if (empty($data['has_sku'])) {
            $data['min_price'] = $data['max_price'] = $data['sell_price'];
        } else {
            list($data['sell_price'], $data['max_price'], $data['total']) = $this->getMinAndMaxPriceByInventory($data['sku']);
            $data['min_price'] = $data['sell_price'];
        }
    }
    //最大最小价格sku
    public function getMinAndMaxPriceByInventory($sku) : array
    {
        $inventoryList = array_column($sku, 'inventory');
        $total = array_sum(array_column($inventoryList, 'total'));
        $sellPrice = [];
        foreach ($inventoryList as $k => $v)
            $sellPrice = array_merge($sellPrice, [$k => $v['sell_price']]);
        asort($sellPrice);
        $minPirce = pos($sellPrice);
        end($sellPrice);
        $maxPrice = pos($sellPrice);;
        return [$minPirce, $maxPrice, $total];
    }

    /**
     * @param Model $model
     * @param $data
     * @param string $method
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function updateAttr(Model $model, &$data, string $method) : void
    {
        $this->$method((int)$model->id, $data['sku_value']);
        $attrList = $this->index($model->id);
        $model->sku_value = $attrList;
        $model->save();
        $data['sku_value'] = (!$attrList) ? [] : $attrList;
        $attrArr = $this->clearSkuAttr($attrList);
        $this->clearSku($attrArr, $data['sku']);
    }

    /**
     * 规格修改
     * @param int $commodityId
     * @param array $data
     */
    public function AttrSave(int $commodityId, array $data):void{
        foreach ($data as $k => $v) {
            $v['commodity_id'] = $commodityId;
            $attrName = IntegralAttrName::create($v);
            $attrName->attrValue()->saveAll($v['attrValue']);
        }
    }

    public function AttrUpdate(int $commodityId, array $data):void{
        $ids = array_column($data, 'id');
        !empty($ids) && IntegralAttrName::whereNotIn('id', $ids)->where(['commodity_id'=>$commodityId])->delete();
        foreach ($data as $k => $v) {
            $ids = array_column($v['attrValue'], 'id');
            !empty($ids) && IntegralAttrValue::whereNotIn('id', $ids)->where(['attr_name_id'=>$v['id']])->delete();
            $v['commodity_id'] = $commodityId;
            if (isset($v['id'])){
                IntegralAttrName::update($v,['id'=>$v['id']]);
                foreach ($v['attrValue'] as $i=>$j){
                    $j['attr_name_id'] = $v['id'];
                    isset($j['id'])?
                        IntegralAttrValue::update($j,['id'=>$j['id']]):
                        IntegralAttrValue::create($j);
                }
            }else{
                $attrName = IntegralAttrName::create($v);
                $attrName->attrValue()->saveAll($v['attrValue']);
            }
        }
    }
    /**
     * 规格
     * @param $commodityId
     * @return Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function index($commodityId) : Collection
    {
        $list = IntegralAttrName::field('id,name,has_pic')
            ->where('commodity_id',$commodityId)
            ->with('attrValue')
            ->select();

        return $list;
    }

    /**
     * @param Collection $data
     * @return array
     */
    public function clearSkuAttr(Collection $data) : array
    {
        $ret = [];
        $data = $data->toArray();
        foreach ($data as $k => $v) {
            $ret[$v['name']]['id'] = $v['id'];
            foreach ($v['attrValue'] as $i => $j) {
                $ret[$v['name']][$j['value']] = $j['id'];
            }
        }
        return $ret;
    }

    /**
     * @param $attrArr
     * @param $skuArr
     */
    public function clearSku($attrArr, &$skuArr)
    {
        foreach ($skuArr as $k => $v) {
            $skuArr[$k]['pvs_value'] = $v['pvs'];
            $pvsValue = '';
            $skuList = explode(',', $v['pvs']);
            $x = 1;
            foreach ($skuList as $j) {
                $skuAttr = explode(':', $j);
                $pvsValue .= $attrArr[$skuAttr[0]]['id'] . ":" . $attrArr[$skuAttr[0]][$skuAttr[1]];
                if ($x != sizeof($skuList)) {
                    $pvsValue .= ",";
                    $x++;
                }
            }
            $skuArr[$k]['pvs'] = $pvsValue;
        }
    }

    /**
     * 删除SKU
     * @param int $id
     */
    private function updateNullSkuAndStore(int $id)
    {
        IntegralSku::where('commodity_id', $id)->delete();
    }

    /**
     *更新
     * @param Model $model
     * @param array $data
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function updateHasSkuAndNullStore(Model $model, array $data)
    {
        if (!empty($model->has_sku)) {
            list($diffIds, $intersectIds) = $this->idDiffAndIntersect(IntegralSku::class, 'commodity_id', $model->id, $data['sku']);
            IntegralSku::destroy($diffIds);
            foreach ($data['sku'] as $k => $v) {
                if (!isset($v['id'])) {
                    $this->saveSkuInventory($model, $v);
                } elseif (in_array($v['id'], $intersectIds)) {
                    $sku = IntegralSku::find($v['id']);
//                    if ($sku->inventory->sell > $v['inventory']['total']) {
//                        throw new Exception("数量有误", HTTP_FORBIDDEN);
//                    }
                    $data['total'] = bcsub((string)$data['total'], (string)$sku->inventory->sell);
                    unset($v['inventory']['sell']);
                    $sku->save($v);
                    IntegralSkuInventory::update($v['inventory'], ['id' => $v['inventory']['id']]);
                }
            }
        } elseif (empty($model->has_sku)) {
            $this->saveSkuInventoryList($model, $data['sku']);
        }
        $model->save($data);
    }

    /**
     *
     * @param $model
     * @param $field
     * @param $id
     * @param $data
     * @return array
     */
    private function idDiffAndIntersect($model, $field, $id, $data)
    {
        $oldIds = $model::where($field, $id)->column('id');
        $newIds = array_column($data, 'id');
        $arrayDiffAndIntersect = arrayDiffAndIntersect($oldIds, $newIds);
        return $arrayDiffAndIntersect;
    }

    /**
     *
     * @param Model $model
     * @param array $skuList
     */
    private function saveSkuInventoryList(Model $model, array $skuList)
    {
        foreach ($skuList as $k => $v)
            $this->saveSkuInventory($model, $v);
    }

    /**
     *
     * @param Model $model
     * @param array $skuData
     */
    private function saveSkuInventory(Model $model, array $skuData)
    {
        $sku = new IntegralSku();
        $skuData['commodity_id'] = $model->id;
        $skuData['inventory']['mall_id'] = $this->mid;
        $sku->inventory = new IntegralSkuInventory();
        $sku->together(['inventory' => $skuData['inventory']])->save($skuData);
    }

}